/*
 *	main.c
 *
 *	id.exe
 *
 *	Mic identification
 */

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include "..\splib\fir.h"
#include "..\waveio\wave.h"

#define FLT2INT(x)  ( (__int16) ( (x) * 32767.0f ) ) 
#define INT2FLT(x)  ( (x) / 32768.0f)       

#define EQU_DP      1
#define EQU_NPOW2   (1<<8)
#define EQU_MU      (1.0f/(float)EQU_NPOW2) // D(x)/N

static void open_files(int argc, char* argv[]);
static void check_format(FILE* f);
static void process_file(FILE* f0, FILE* f1, FILE* fout);

FILE* f0;
FILE* f1;
FILE* ferr;
FILE* fequ;
FILE* fout;

void main(int argc, char* argv[])
{
    static WAVE wave = 
    {
        'FFIR', 0, 'EVAW', 
        ' tmf', 16, 
        1, // AudioFormat
        1, // NumChannels
        8000, // SampleRate
        8000*1*2, // ByteRate
        1*2, // BlockAlign
        16, // BitsPerSample
        'atad', 0
    };

#ifdef EQU_DP
    double equ_w[EQU_NPOW2];
#else
    float equ_w[EQU_NPOW2];
#endif
    float equ_z[EQU_NPOW2];
    float delay_z[EQU_NPOW2/2];
    int equ_idx, delay_idx;

    __int16 inbuf0[EQU_NPOW2];
    __int16 inbuf1[EQU_NPOW2];
    __int16 outbuf[EQU_NPOW2];
    __int16 outbuf2[EQU_NPOW2];

    float x, d, y, err;
    int i, j;

    open_files(argc, argv);

	if(1 != fwrite(&wave, sizeof(WAVE), 1, fout))
	{
		perror("can not write WAVE header");
		exit(1);
	}
	if(1 != fwrite(&wave, sizeof(WAVE), 1, fequ))
	{
		perror("can not write WAVE header");
		exit(1);
	}
	if(1 != fwrite(&wave, sizeof(WAVE), 1, ferr))
	{
		perror("can not write WAVE header");
		exit(1);
	}

    firInit(equ_z, &equ_idx, EQU_NPOW2);

    for(i = 0; i < EQU_NPOW2; ++i)
    {
        equ_w[i] = 0;
    }
    //equ_w[EQU_NPOW2/2-1] = 1.0f;

    firInit(delay_z, &delay_idx, EQU_NPOW2/2);

    for(j = 0;;++j)
    {
        if(EQU_NPOW2 != fread(inbuf0, sizeof(__int16), EQU_NPOW2, f0))
        {
            break;
        }
        if(EQU_NPOW2 != fread(inbuf1, sizeof(__int16), EQU_NPOW2, f1))
        {
            break;
        }

        for(i = 0; i < EQU_NPOW2; ++i)
        {
#if 1
            x = INT2FLT(inbuf0[i]);
            d = INT2FLT(inbuf1[i]);

            //d = firDelay(d, delay_z, &delay_idx, EQU_NPOW2/2);

#ifdef EQU_DP
            y = firRun_DP(x, equ_z, equ_w, &equ_idx, EQU_NPOW2);
#else
            y = firRun(x, equ_z, equ_w, &equ_idx, EQU_NPOW2);
#endif
#else
            x = INT2FLT(inbuf0[i]);

            d = x * 0.5f;
            d = firDelay(d, delay_z, &delay_idx, EQU_NPOW2/2);

            y = firRun(x, equ_z, equ_w, &equ_idx, EQU_NPOW2);
#endif

            outbuf[i] = FLT2INT(y);

            err = d - y;

            outbuf2[i] = FLT2INT(err);

#ifdef EQU_DP
            firLMS_DP(equ_w, equ_z, equ_idx, err, EQU_MU, EQU_NPOW2);
#else
            firLMS(equ_w, equ_z, equ_idx, err, EQU_MU, EQU_NPOW2);
#endif
        }
        fwrite(outbuf, sizeof(__int16), EQU_NPOW2, fout);
        fwrite(outbuf2, sizeof(__int16), EQU_NPOW2, ferr);

        for(i = 0; i < EQU_NPOW2; ++i)
        {
            outbuf[i] = FLT2INT(equ_w[i]*0.5f);
        }
        fwrite(outbuf, sizeof(__int16), EQU_NPOW2, fequ);
    }

    // input files
    fclose(f0);
    fclose(f1);

    // fout
 	wave.SubChunk2Size = sizeof(__int16) * j * EQU_NPOW2;
	wave.ChunkSize = wave.SubChunk2Size + 36;
	fseek(fout, 0, SEEK_SET);
	fwrite(&wave, 1, sizeof(WAVE), fout);
    fclose(fout);

    // ferr
 	wave.SubChunk2Size = sizeof(__int16) * j * EQU_NPOW2;
	wave.ChunkSize = wave.SubChunk2Size + 36;
	fseek(ferr, 0, SEEK_SET);
	fwrite(&wave, 1, sizeof(WAVE), ferr);
    fclose(ferr);

    // fequ
 	wave.SubChunk2Size = sizeof(__int16) * j * EQU_NPOW2 * EQU_NPOW2;
	wave.ChunkSize = wave.SubChunk2Size + 36;
	fseek(fequ, 0, SEEK_SET);
	fwrite(&wave, 1, sizeof(WAVE), fequ);
    fclose(fequ);

}   // main

void open_files(int argc, char* argv[])
{
    if(argc < 3)
    {
        printf("Not enough arguments\n");
        exit(1);
    }
    if(NULL == (f0 = fopen(argv[1], "rb")))
    {
        printf("Can't open for reading %s\n", argv[1]);
        exit(1);
    }
    check_format(f0);
    if(NULL == (f1 = fopen(argv[2], "rb")))
    {
        printf("Can't open for reading %s\n", argv[2]);
        exit(1);
    }
    check_format(f1);

    if(NULL == (fout = fopen("id.wav", "wb")))
    {
        printf("Can't open for writing %s\n", argv[3]);
        exit(1);
    }
    if(NULL == (fequ = fopen("equ.wav", "wb")))
    {
        printf("Can't open for writing %s\n", argv[4]);
        exit(1);
    }
    if(NULL == (ferr = fopen("err.wav", "wb")))
    {
        printf("Can't open for writing %s\n", argv[5]);
        exit(1);
    }
}

void check_format(FILE* f)
{
    WAVE wave;

	if( sizeof(WAVE) != fread(&wave, 1, sizeof(WAVE), f) )
	{
		perror("can not read header");
		exit(1);
	}

    if(	('FFIR' != wave.ChunkID) || ('EVAW' != wave.Format) || (' tmf' != wave.SubChunk1ID) || ('atad' != wave.SubChunk2ID))
	{
		printf("Wrong format\n");
		exit(1);
	}

	if((1 != wave.NumChannels) || (16 != wave.BitsPerSample) || (1 != wave.AudioFormat))
	{
		printf("Wrong sample format\n\n");

		printf("Sample rate %d, ", wave.SampleRate);
		printf("Number of channels %d, ", wave.NumChannels);
		printf("Bits per sample %d, ", wave.BitsPerSample);
		printf("Audio format %d\n", wave.AudioFormat);

		exit(1);
	}
}   // check_format
